#include "utilities.h"

void err_msg(const char *fmt, ...);
void err_ret(const char *fmt, ...);
void err_sys(const char *fmt, ...);
void err_quit(const char *fmt, ...);
char *numtomsg(int num);

// readn implemention
ssize_t readn(int fd, void *ptr, size_t n)
{
	size_t nleft;
	ssize_t nread;

	nleft = n;
	while (nleft > 0) {
		if ((nread = read(fd, ptr, nleft)) < 0)	{
			if (nleft == n)
				return -1;
			else 
				break;
		} else if (nread == 0) {
			break;	
		}
		nleft -= nread;
		ptr += nread;
	}
	return (n - nleft);
}

// writen implemention
ssize_t writen(int fd, const void *ptr, size_t n)
{
	size_t nleft;
	ssize_t nwriten;

	nleft = n;
	while (nleft > 0) {
		if ((nwriten = write(fd, ptr, nleft)) < 0) {
			if (nleft == n)	
				return (-1);
			else 
				break;
		} else if (nwriten == 0) {
			break;	
		}	
		nleft -= nwriten;
		ptr += nwriten;
	}
	return (n - nleft);
}

// send msg to host
int send_msg(int fd, int num, ...)
{
	int n; 
	va_list ap;
	char buf[MAXSIZE];
	char *pstring;

	pstring = (char *)numtomsg(num);	
	va_start(ap, num);
	vsnprintf(buf, sizeof(buf), pstring, ap);
	va_end(ap);

	while ((n =	writen(fd, buf, strlen(buf))) == -1) {
		if (errno == EINTR)	
			continue;
		else 
			return -1;
	}
	return 0;
}

// receive msg from host
int recv_msg(int fd, char *buf, int buflen)
{
	int n;

	while ((n = read(fd, buf, buflen)) == -1){
		if (errno == EINTR)	
			continue;
		else 
			return (-1);
	}	
	return 0;
}

// trim string of "\r\n"
void trimstring(char *str, int len)
{
	char *end = str + len - 1;

	while (((*end) != '\r') && ((*end) != '\n'))
		end--;
	while ((*end) == '\r' || (*end) == '\n')
		end--;
	*(++end) = '\0';
}

int isroot()
{
	return (geteuid() == 0);
}

int tcp_listen(const char *hostname, const char *serv, socklen_t *addrlenp) {
    int listenfd, n;
    const int on = 1;
    struct addrinfo hints, *res, *ressave;

    bzero(&hints, sizeof(struct addrinfo));
    hints.ai_family = AF_UNSPEC;
    hints.ai_flags = AI_PASSIVE;
    hints.ai_socktype = SOCK_STREAM;

    if ((n = getaddrinfo(hostname, serv, &hints, &res)) !=0 ) {
        err_quit("tcp_listen error for %s, %s:%s", 
                hostname, serv, gai_strerror(n)); 
    }
    ressave = res;

    do {
        listenfd = 
            socket(res->ai_family, res->ai_socktype, res->ai_protocol);
        if (listenfd < 0)   
            continue;

        setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
        if (bind(listenfd, res->ai_addr, res->ai_addrlen) == 0)
            break;
        close(listenfd);
    } while((res = res->ai_next) != NULL);

    if (res == NULL)
        err_sys("tcp_listen error for %s,%s", hostname, serv);

    listen(listenfd, LISTENQ);

    if (addrlenp)
        *addrlenp = res->ai_addrlen;

    freeaddrinfo(ressave);

    return listenfd;
}

